package client.view.twothousandfortyeight;

import java.util.Observable;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.MessageBox;

import client.view.Board;
import client.view.View;

public class Game2048View extends Observable implements View, Runnable { 
	private Board board;
	private Label score;
	private int userCommand;
	private Point startDrag;
	private Point endDrag;
	
	private int[][] currentBoard;
	private int currentScore;
	private String currentMessageTitle;
	private String currentMessageText;
	private int currentMessageStyle;
	private int currentUserChoise;
	private boolean lockedControls;
	
	public Game2048View(Label score, Board board, int boardSize) {
		this.board = board;
		this.score = score;
		
		board.initBoard(boardSize, boardSize, SWT.BORDER, mouseAdapter);
		
		initListeners();
	}
	
	@Override
	public int getUserCommand() {
		return userCommand;
	}
	
	@Override
	public void setUserCommand(int userCommand)
	{
		this.userCommand = userCommand;
		
		setChanged();
		notifyObservers();
	}
	
	@Override
	public void updateDisplay(int[][] data, int score) {
		currentBoard = data;
		currentScore = score;
		board.getDisplay().syncExec(this);
	}
	
	@Override
	public void run() {
		score.setText(" Score:   " + currentScore);
		board.updateBoard(currentBoard);
	}
	
	@Override
	public void setLockControls(boolean lock) {
		lockedControls = lock;
	}
	
	@Override
	public boolean getLockControls() {
		return lockedControls;
	}
	
	@Override
	public boolean showEndGame(int gameState) {
		switch (gameState) {
			// Lost game
			case 1: {
				currentMessageTitle = "Game Over";
				currentMessageText = "Game Over :(";
				currentMessageStyle = SWT.ICON_INFORMATION | SWT.OK;
				board.getDisplay().syncExec(showMessage);
				
				break;
			}
			// Won game
			case 2: {
				currentMessageTitle = "You win";
				currentMessageText = "You win!\nPress YES to continue playing or NO to end the game.";
				currentMessageStyle = SWT.ICON_INFORMATION | SWT.YES | SWT.NO;
				board.getDisplay().syncExec(showMessage);
				
				if (currentUserChoise == SWT.YES) {
					return false;
				}
				
				break;
			}
		}

		return true;
	}
	
	Runnable showMessage = new Runnable() {
	    @Override
	    public void run() {
	    	MessageBox messageBox = new MessageBox(board.getShell(), currentMessageStyle);
			messageBox.setText(currentMessageTitle);
			messageBox.setMessage(currentMessageText);
			currentUserChoise = messageBox.open();
	    }
	};
	
	private void initListeners() {
		board.addKeyListener(keyListener); 
	}
	
	KeyListener keyListener = new KeyListener() {
		@Override
		public void keyReleased(KeyEvent arg0) {
		}
		
		@Override
		public void keyPressed(KeyEvent event) {
			if (!getLockControls()) {
				switch (event.keyCode) {
					case SWT.ARROW_UP: 
						setUserCommand(1);
						break;
					case SWT.ARROW_DOWN: 
						setUserCommand(2);
						break;
					case SWT.ARROW_LEFT: 
						setUserCommand(3);
						break;
					case SWT.ARROW_RIGHT: 
						setUserCommand(4);
						break;
					default:
						//Ignore the incorrect key press
						setUserCommand(0);
						break;			
				}
			}
		}
	};
	
	MouseAdapter mouseAdapter = new MouseAdapter() {  
        public void mouseDown(MouseEvent e){  
            startDrag = new Point(e.x, e.y);  
        }
        
        public void mouseUp(MouseEvent e) {  
        	endDrag = new Point(e.x, e.y); 

        	if (!getLockControls() && startDrag != null && endDrag != null) {
	        	int deltaX = startDrag.x - endDrag.x;
	        	int deltaY = startDrag.y - endDrag.y;
	            
	            if ((deltaY>0 && deltaX>0 && deltaX>deltaY) || (deltaY<0 && deltaX>0 && deltaX>Math.abs(deltaY))) {
	            	//Move Left
	            	setUserCommand(3);
	            }
	            else if ((deltaY>0 && deltaX>0 && deltaX<deltaY) || (deltaY>0 && deltaX<0 && Math.abs(deltaX)<deltaY)) {
	            	//Move Up
	            	setUserCommand(1);
	            }
	            else if ((deltaY<0 && deltaX>0 && deltaX<Math.abs(deltaY)) || (deltaY<0 && deltaX<0 && Math.abs(deltaX)<Math.abs(deltaY))) {
	            	//Move Down
	            	setUserCommand(2);
	            }
	            else if ((deltaY>0 && deltaX<0 && Math.abs(deltaX)>deltaY) || (deltaY<0 && deltaX<0 && Math.abs(deltaX)>Math.abs(deltaY))) {
	            	//Move Right
	            	setUserCommand(4);
	            }
	            else {
	            	setUserCommand(0);
	            }
	            
	            startDrag = null;
	            endDrag = null;
	        }
        }  
    };
}